package org.smart4j.framework;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.smart4j.framework.bean.Data;
import org.smart4j.framework.bean.Handler;
import org.smart4j.framework.bean.Param;
import org.smart4j.framework.bean.View;
import org.smart4j.framework.helper.BeanHelper;
import org.smart4j.framework.helper.ConfigHelper;
import org.smart4j.framework.helper.ControllerHelper;
import org.smart4j.framework.helper.HelperLoader;
import org.smart4j.framework.helper.RequestHelper;
import org.smart4j.framework.helper.ServletHelper;
import org.smart4j.framework.helper.UploadHelper;
import org.smart4j.framework.util.ArrayUtil;
import org.smart4j.framework.util.CodecUtil;
import org.smart4j.framework.util.JsonUtil;
import org.smart4j.framework.util.ReflectUtil;
import org.smart4j.framework.util.StreamUtil;

/**
 * description: 请求转发器 --- web 控制器
 * @version v1.0
 * @author w
 * @date 2018年9月1日下午4:35:52
 */
@WebServlet(urlPatterns ={"/*","/dd"} ,loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DispatcherServlet() {
        super();
    }

	/**
	 * init smart-framework
	 */
    @Override
	public void init(ServletConfig config) throws ServletException {
    	System.out.println("running ....");
		// 初始化相关 helper 类
    	HelperLoader.init();
    	// 获取 ServletContext 对象 
    	ServletContext servletContext = config.getServletContext();
    	
    	// 注册处理 jsp的 Servlet
    	ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
    	jspServlet.addMapping(ConfigHelper.getAppJspPath()+"*");
    	
    	// 注册处理静态资源的默认 Servlet ( *.css , *.js 等文件)
    	ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
    	defaultServlet.addMapping(ConfigHelper.getAppAssetPath());
    	
    	UploadHelper.init(servletContext);
	}

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
    @Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 初始化 request , response 对象 到 ServletHelper 中
    	ServletHelper.init(request, response);
    	try {
			// 获取请求方法与路径
			String method = request.getMethod().toLowerCase();
			String path = request.getPathInfo();
			// 获取Action 处理器
			Handler handler = ControllerHelper.getHandler(method, path);
			if(null != handler){
				// 获取 controller 类及其 Bean 实例
				Class<?> controllerClass = handler.getControllerClass();
				Object controllerBean = BeanHelper.getBean(controllerClass);
				
				Param param ;
				if(UploadHelper.isMultipart(request)){
					// 如果是文件上传请求
					param = UploadHelper.createParam(request);
				}else{
					param = RequestHelper.createParam(request);
				}
				// 创建请求参数对象
				Map<String,Object> paramMap = new HashMap<>();
				Enumeration<String> paramNames = request.getParameterNames();
				while(paramNames.hasMoreElements()){
					// 表单元素中 name 属性 名称 (<input name="userName" />)
					String paramName = paramNames.nextElement();
					String paramValue = request.getParameter(paramName);
					paramMap.put(paramName, paramValue);
				}
				
				// 调用Action 方法
				Method actionMethod = handler.getActionMethod();
				Object result ;
				if(param.isEmpty()){
					result = ReflectUtil.invokeMethod(controllerBean, actionMethod);
				}else{
					result = ReflectUtil.invokeMethod(controllerBean, actionMethod, param);
				}
				// 处理Action 方法返回值
				if(result instanceof View){
					// 返回的是 JSP 页面
					handleViewResult(request, response, result);
				}else if(result instanceof Data){
					// 返回JSON数据
					handleDataResult(response, result);
				}
			} // end if handler
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			ServletHelper.destroy();
		}
    }
    
    private void handleViewResult(HttpServletRequest request, HttpServletResponse response, Object result)
			throws IOException, ServletException {
		View view =(View)result;
		String jspPath = view.getPath();
		if(StringUtils.isNotEmpty(jspPath)){
			if(jspPath.startsWith("/")){
				response.sendRedirect(request.getContextPath()+jspPath);
			}else{
				Map<String, Object> model = view.getModel();
				for(Map.Entry<String, Object> entry : model.entrySet()){
					request.setAttribute(entry.getKey(), entry.getValue());
				}
				// 转发到对应的jsp页面
				request.getRequestDispatcher(ConfigHelper.getAppJspPath()+jspPath).forward(request, response);
			}
		}
	}
    
	private void handleDataResult(HttpServletResponse response, Object result) throws IOException {
		Data data = (Data)result;
		Object model = data.getModel();
		if(null != model){
			response.setContentType("appliaction/json");
			response.setCharacterEncoding("UTF-8");
			PrintWriter writer = response.getWriter();
			String json = JsonUtil.toJson(model);
			writer.write(json);
			writer.flush();
			writer.close();
		}
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	 @Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	 @Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}
